/*
     Copyright 2007 Joseph M. Ferner

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System.IO;
using log4net;
using OpenServers.Net.Common.FileSystem;
using OpenServers.Net.FtpServer.State;

namespace OpenServers.Net.FtpServer.Command {
    /// <summary>
    ///     <para>
    ///         <b>RETRIEVE (RETR)</b><br/>
    ///         This command causes the server-DTP to transfer a copy of the
    ///         file, specified in the pathname, to the server- or user-DTP
    ///         at the other end of the data connection.  The status and
    ///         contents of the file at the server site shall be unaffected.
    ///     </para>
    ///     <para>
    ///         <b>Format</b><br/>
    ///         <code>RETR [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code>
    ///     </para>
    ///     <para>
    ///         <b>Success:</b>
    ///         <list type="bullet">
    ///             <item><term>110</term><description>
    ///                 Restart marker reply.
    ///                 In this case, the text is exact and not left to the
    ///                 particular implementation; it must read: MARK yyyy = mmmm
    ///                 Where yyyy is User-process data stream marker, and mmmm
    ///                 server's equivalent marker (note the spaces between markers and "=").
    ///             </description></item>
    ///             <item><term>125</term><description>Data connection already open; transfer starting.</description></item>
    ///             <item><term>150</term><description>File status okay; about to open data connection.</description></item>
    ///             <item><term>226</term><description>Closing data connection. Requested file action successful (for example, filetransfer or file abort).</description></item>
    ///             <item><term>250</term><description>Requested file action okay, completed.</description></item>
    ///         </list>
    ///     </para>
    ///     <para>
    ///         <b>Errors:</b>
    ///         <list type="bullet">
    ///             <item><term>421</term><description>Service not available, closing control connection.</description></item>
    ///             <item><term>425</term><description>Can't open data connection.</description></item>
    ///             <item><term>426</term><description>Connection closed; transfer aborted.</description></item>
    ///             <item><term>450</term><description>Requested file action not taken. File unavailable (e.g., file busy).</description></item>
    ///             <item><term>451</term><description>Requested action aborted. Local error in processing.</description></item>
    ///             <item><term>500</term><description>Syntax error, command unrecognized.</description></item>
    ///             <item><term>501</term><description>Syntax error in parameters or arguments.</description></item>
    ///             <item><term>530</term><description>Not logged in.</description></item>
    ///             <item><term>550</term><description>Requested action not taken. File unavailable (e.g., file not found, no access).</description></item>
    ///         </list>
    ///     </para>
    /// </summary>
    public class RetrieveCommand : BaseSendDataCommand {
        private static readonly ILog log = LogManager.GetLogger(typeof(RetrieveCommand));

        /// <summary>
        /// sends file from the server to the client.
        /// </summary>
        public override void PerformCommand(IFtpServer server, FtpState state, string arguments) {
            if (string.IsNullOrEmpty(arguments)) {
                state.Listener.Send(state, server.Messages.Get501());
            } else {
                string filePath = GetFilePath(state, arguments);
                IFile file = server.FileSystem.GetFile(filePath);
                if (file == null || !file.Exists) {
                    state.Listener.Send(state, server.Messages.Get550(Reason550.FileNotFound));
                } else {
                    if (server.SecurityProvider.CanRead(state.User, file)) {
                        Stream fileDataStream = file.OpenInputStream();
                        state.Listener.Send(state, server.Messages.Get150(arguments));
                        log.DebugFormat("begin sending [{0}]", filePath);
                        SendData(server, state, fileDataStream);
                    } else {
                        state.Listener.Send(state, server.Messages.Get550(Reason550.AccessDenied));
                    }
                }
            }
        }
    }
}
